#ifndef UNITTEST_HPP
#define UNITTEST_HPP
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <utility>
using std::pair;
#include "Util.hpp"

#ifndef NDEBUG
#define Assert(expr) ((expr)?1:(criticalFail(#expr, __LINE__, __FILE__)))
#else
#define Assert(expr) 1
#endif

int criticalFail(const char *expr, int line, const char *file);

int testFailed(const char *condition, int line, const char *file);
int testFailed(const char *condition, int line, const char *file, string note);

void beginTest(string description);
void endTest();

void runTests();
void summarizeTests();

#define testAssert(expr) \
	((expr)?1:testFailed(#expr, __LINE__, __FILE__))
#define testAssertStr(expr, note) \
	((expr)?1:testFailed(#expr, __LINE__, __FILE__, note))

typedef void (*UnitTestFunc)();
void addTestSet(UnitTestFunc func, const char *name);
#define TEST_SET(name) \
	void testSet_##name(); \
	void addTestSet_##name() { \
		addTestSet(testSet_##name, #name); \
	} \
	StartupCaller testSetCaller_##name(addTestSet_##name); \
	void testSet_##name()

#define MEMBER_TEST_SET(classname, name) \
	void addTestSet_##name() { \
		addTestSet(classname::testSet_##name, #name); \
	} \
	StartupCaller testSetCaller_##name(addTestSet_##name); \
	void classname::testSet_##name()
#define HAS_TEST_SET(name) \
	static void testSet_##name(); \
	friend void addTestSet_##name();

#endif
